/*
    This file is part of Raptor.

    Raptor is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Raptor is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Raptor.  If not, see <http://www.gnu.org/licenses/>.

 */

#include "serienjunkies_org.h"


pluginUrlContainer::pluginUrlContainer()
{
    reHost = QRegExp("^download.serienjunkies.org$");
    reLink = QRegExp("^http://download.serienjunkies.org/(?:.*)$");

    connect(&http, SIGNAL(requestFinished(int, bool)), this, SLOT(slot_http_requestFinished(int, bool)));
    connect(&http, SIGNAL(readyRead(const QHttpResponseHeader &)), this, SLOT(slot_http_readyRead(const QHttpResponseHeader &)));
    connect(&http, SIGNAL(dataReadProgress(int, int)), this, SLOT(slot_http_dataReadProgress(int, int)));
    connect(&http, SIGNAL(sslErrors(const QList<QSslError> &)), this, SLOT(slot_http_sslErrors(const QList<QSslError> &)));

    reBlocked = QRegExp("<TD ALIGN=CENTER>Du hast das Download-Limit &amp;uuml;berschritten! Bitte versuche es sp&amp;auml;ter nocheinmal.</TD>");
    reCaptcha = QRegExp("<TD VALIGN=\"TOP\" id=\"cwid\"><div title=\"Seite neu laden / Reload\" onClick=\"window.location.reload\\(\\)\" id=\"preload\" href=\"#\"></div></TD>");
    reCaptchaForm = QRegExp("<FORM ACTION=\"([^\"]*)\"");
    reGetString = QRegExp("<INPUT TYPE=\"HIDDEN\" NAME=\"s\" VALUE=\"([^\"]*)\">");
    reCaptchaUrl = QRegExp("<IMG(?:[^>]*)SRC=\"([^\"]*)\"(?:[^>]*)\">");
}

void pluginUrlContainer::setProxy(QNetworkProxy const& proxy)
{
    Q_UNUSED(proxy);
    //todo:
    //this->http.setProxy(proxy);
}

void pluginUrlContainer::start(QUrl const& url, QString const& captchaDir)
{
    this->_abort = false;
    step = 0;
    links.clear();
    maskedLinks.clear();
    framedLinks.clear();

    this->_captchaDir = captchaDir;
    waitingId = request(url, "GET", QByteArray(), QMap<QString, QString>());
}

void pluginUrlContainer::abort()
{
    this->_abort = true;
    this->http.abort();
}

void pluginUrlContainer::setCaptcha(QString const& captcha)
{
    if(step == 2)
    {
        step = 3;

        QByteArray post = "s=" + QUrl::toPercentEncoding(captchaText) + "&c=" + QUrl::toPercentEncoding(captcha) + "&action=Download";
        QMap<QString, QString> header;
        header.insert("Content-Type", "application/x-www-form-urlencoded");

        waitingId = request(QUrl(captchaLink), "POST", post, header);
    } else
    {
        this->_errorString = tr("Wrong time for captcha.");
        finish(true);
    }
}

bool pluginUrlContainer::isValidUrl(QUrl const& url)
{
    if(reLink.indexIn(url.toString()) != -1)
    {
        return true;
    }

    return false;
}


int pluginUrlContainer::request(QUrl const& url, QString const& method, QByteArray const& post, QMap<QString, QString> const& headerData, QIODevice *io)
{
    response = "";

    QHttpRequestHeader header(method, url.path());
    header.setValue("Host", url.host());


    QMap<QString, QString>::const_iterator it = headerData.constBegin();
    for(;it!=headerData.constEnd(); ++it)
    {
        header.setValue(it.key(), it.value());
    }

    if(this->cookie != "") header.setValue("Cookie", this->cookie);

    if(url.toString().left(5) == "https")
    {
        this->http.setHost(url.host(), QHttp::ConnectionModeHttps);
    } else
    {
        this->http.setHost(url.host());
    }

    if(io == 0)
    {
        return this->http.request(header, post);
    } else
    {
        return this->http.request(header, post, io);
    }
}

void pluginUrlContainer::finish(bool const& error)
{
    emit progressChanged(100);
    maskedLinks.clear();
    framedLinks.clear();
    emit finished(links, error);
}

void pluginUrlContainer::loadCaptcha()
{
    if(reBlocked.indexIn(page) != -1)
    {
        this->_errorString = tr("IP blocked.");
        finish(true);
    } else if(reCaptcha.indexIn(page) != -1)
    {
        if(reCaptchaForm.indexIn(page) != -1)
        {
            captchaLink = "http://download.serienjunkies.org" + reCaptchaForm.cap(1);

            if(reGetString.indexIn(page) != -1)
            {
                captchaText = reGetString.cap(1);

                if(reCaptchaUrl.indexIn(page) != -1)
                {
                    QString captchaUrl = "http://download.serienjunkies.org" + reCaptchaUrl.cap(1);

                    step = 1;

                    this->_captchaFile = new QTemporaryFile(this->_captchaDir + QDir::separator() + "serienjunkies_org" + "_XXXXXX.png");
                    this->_captchaFile->setAutoRemove(false);

                    if(this->_captchaFile->open())
                    {
                        waitingId = request(QUrl(captchaUrl), "POST", QByteArray(), QMap<QString, QString>(), this->_captchaFile);
                    } else
                    {
                        this->_errorString = tr("Cannot create captcha file.");
                        finish(true);
                    }
                } else
                {
                    this->_errorString = tr("Captcha url not found.");
                    finish(true);
                }
            } else
            {
                this->_errorString = tr("Captcha text not found.");
                finish(true);
            }
        } else
        {
            this->_errorString = tr("Captcha form not found.");
            finish(true);
        }
    } else
    {
        qDebug() << page;
        this->_errorString = tr("Unknown error.");
        finish(true);
    }
}

//slots ->
void pluginUrlContainer::slot_http_requestFinished(int id, bool error)
{
    Q_UNUSED(error);
    
    if(this->_abort)
    {
        if(this->_captchaFile->isOpen()) this->_captchaFile->close();
        this->_errorString = http.errorString();
        finish(true);
        return;
    }

    if(waitingId != id) return;
    page = QString(response);

    switch(step)
    {
        default:
        case 0:
        {
            loadCaptcha();
            break;
        }

        case 1:
        {
            if(this->_captchaFile)
            {
                this->_captchaFile->close();
                step = 2;
                emit captcha(this->_captchaFile->fileName());
            } else
            {
                this->_errorString = tr("Captcha file does not exist.");
                finish(true);
            }
            break;
        }

        case 2:
        {

            break;
        }

        case 3:
        {
            if(reCaptcha.indexIn(page) != -1)
            {
                if(this->_captchaFile)
                {
                    this->_captchaFile->remove();
                }

                loadCaptcha();
                break;
            }

            QRegExp reLinks("<FORM ACTION=\"http://download.serienjunkies.org([^\"]*)\"");
            if(reLinks.indexIn(page) != -1)
            {
                int pos = 0;

                maskedLinks.clear();
                while((pos = reLinks.indexIn(page, pos)) != -1)
                {
                    maskedLinks.append(reLinks.cap(1));

                    pos += reLinks.matchedLength();
                }

                if(maskedLinks.size() > 0)
                {
                    step = 4;
                    counter = 1;

                    QString tmpLink = "http://download.serienjunkies.org" + maskedLinks.at(0);

                    waitingId = request(QUrl(tmpLink), "GET", QByteArray(), QMap<QString, QString>());
                } else
                {
                    finish(false);
                }
            } else
            {
                this->_errorString = tr("No links found.");
                finish(true);
            }

            break;
        }

        case 4:
        {
            int tmpProgress = (50 * counter) / maskedLinks.size();

            if(tmpProgress < 0) tmpProgress = 0;
            if(tmpProgress > 50) tmpProgress = 50;

            emit progressChanged(tmpProgress);

            QRegExp reFrame("<FRAME SRC=\"http://download.serienjunkies.org([^\"]*)\"");

            if(reFrame.indexIn(page) != -1)
            {
                framedLinks.append(reFrame.cap(1));
            }

            if(counter < maskedLinks.size())
            {
                QString tmpLink = "http://download.serienjunkies.org" + maskedLinks.at(counter);
                ++counter;

                waitingId = request(QUrl(tmpLink), "GET", QByteArray(), QMap<QString, QString>());
            } else
            {                
                if(framedLinks.size() > 0)
                {
                    step = 5;
                    counter = 1;

                    QString tmpLink = "http://download.serienjunkies.org" + framedLinks.at(0);

                    waitingId = request(QUrl(tmpLink), "GET", QByteArray(), QMap<QString, QString>());
                } else
                {
                    finish(false);
                }
            }

            break;
        }

        case 5:
        {            
            int tmpProgress = (50 * counter) / maskedLinks.size();

            if(tmpProgress < 0) tmpProgress = 0;
            if(tmpProgress > 50) tmpProgress = 50;

            emit progressChanged(50 + tmpProgress);

            if(this->http.lastResponse().hasKey("Location"))
            {
                links.append(this->http.lastResponse().value("Location"));
            }

            if(counter < framedLinks.size())
            {
                QString tmpLink = "http://download.serienjunkies.org" + framedLinks.at(counter);
                ++counter;

                waitingId = request(QUrl(tmpLink), "GET", QByteArray(), QMap<QString, QString>());
            } else
            {
                finish(false);
            }

            break;
        }
    }
}

void pluginUrlContainer::slot_http_readyRead(const QHttpResponseHeader & resp)
{
    Q_UNUSED(resp);
    response.append(this->http.readAll());
}

void pluginUrlContainer::slot_http_dataReadProgress(int done, int total)
{
    Q_UNUSED(done);
    Q_UNUSED(total);
}

void pluginUrlContainer::slot_http_sslErrors(const QList<QSslError> & errors)
{
    //todo:
    Q_UNUSED(errors);
    this->http.ignoreSslErrors();
}
//<- slots

Q_EXPORT_PLUGIN2(serienjunkies_org, pluginUrlContainer);
